package com.tang.kite.wrapper.where

import com.tang.kite.function.SFunction
import com.tang.kite.paginate.OrderItem
import com.tang.kite.wrapper.Wrapper
import kotlin.reflect.KMutableProperty1

/**
 * Where order by wrapper
 *
 * @author Tang
 */
abstract class AbstractOrderByWrapper<R, T>(

    private val wrapper: Wrapper<T>,

    private val columns: MutableList<OrderItem<*>> = mutableListOf()

) : WrapperBuilder<T> {

    protected var orderByInstance: R? = null

    private fun getInstance(): R {
        return orderByInstance ?: throw IllegalStateException("OrderBy instance is not initialized")
    }

    /**
     * Order by operation
     *
     * @param orderBys order by items
     * @return R
     */
    @SafeVarargs
    fun <E> orderBy(vararg orderBys: OrderItem<E>): R {
        columns.addAll(orderBys)
        return getInstance()
    }

    /**
     * Order by operation
     *
     * @param column column name
     * @param asc asc or desc
     * @return R
     */
    fun orderBy(column: String, asc: Boolean = true): R {
        return orderBy(OrderItem<T>(column, asc))
    }

    /**
     * Order by operation
     *
     * @param column column name
     * @return R
     */
    fun orderBy(column: String): R {
        return orderBy(column, true)
    }

    /**
     * Order by operation
     *
     * @param column column property
     * @param asc asc or desc
     * @return R
     */
    fun <E> orderBy(column: KMutableProperty1<E, *>, asc: Boolean = true): R {
        return orderBy(OrderItem(column, asc))
    }

    /**
     * Order by operation
     *
     * @param column column function
     * @param asc asc or desc
     * @return R
     */
    fun <E> orderBy(column: SFunction<E, *>, asc: Boolean = true): R {
        return orderBy(OrderItem(column, asc))
    }

    /**
     * Order by ascending with column name
     *
     * @param column column name
     * @return R
     */
    fun orderByAsc(column: String): R {
        return orderBy(column, true)
    }

    /**
     * Order by descending with column name
     *
     * @param column column name
     * @return R
     */
    fun orderByDesc(column: String): R {
        return orderBy(column, false)
    }

    /**
     * Order by ascending with property reference
     *
     * @param column column property
     * @return R
     */
    fun <E> orderByAsc(column: KMutableProperty1<E, *>): R {
        return orderBy(column, true)
    }

    /**
     * Order by descending with property reference
     *
     * @param column column property
     * @return R
     */
    fun <E> orderByDesc(column: KMutableProperty1<E, *>): R {
        return orderBy(column, false)
    }

    /**
     * Order by ascending with SFunction
     *
     * @param column column function
     * @return R
     */
    fun <E> orderByAsc(column: SFunction<E, *>): R {
        return orderBy(column, true)
    }

    /**
     * Order by descending with SFunction
     *
     * @param column column function
     * @return R
     */
    fun <E> orderByDesc(column: SFunction<E, *>): R {
        return orderBy(column, false)
    }

    /**
     * Build the wrapper
     *
     * @return Wrapper instance
     */
    override fun build(): Wrapper<T> {
        return wrapper
    }

    fun appendSqlNode(orderBy: MutableList<OrderItem<*>>) {
        orderBy.addAll(columns)
    }

}
